[SW Expert Academy] 9092. 마라톤
Posted on
문제 :
승원이는 마라톤 동아리 “나는 마라토너다” 의 회장으로, 2018년 새해를 맞아 마라톤 대회를 열었다.
마라톤 코스는 n개의 체크포인트로 구성되어 있으며, 1번 체크포인트에서 시작해서 2, 3, 4번 순서대로 모든 체크 포인트를 순서대로 방문한 후n번 체크포인트에서 끝나야지 마라톤이 끝난다.
각 체크포인트는 2차원 좌표평면의 정수 좌표로 주어지며, 두 체크포인트 간의 거리는 택시 거리로 계산된다. 즉, 두 점 (x1 , y1) 과 (x2 , y2) 간의 거리는|x1 - x2| + |y1 - y2|로 계산된다.
현수는 “나는 마라토너다” 의 동아리원이다. 처음에 현수는 굳은 마음가짐으로 대회 참가를 결심했지만, 막상 대회가 다가오니 달리기가 싫어졌다.
그래서 현수는 중간에 있는 체크포인트 k 개를 몰래 건너뛰려 한다.
단, 1번 체크포인트와 n번 체크포인트를 건너뛰면 너무 눈치가 보이니 두 체크포인트는 건너뛰지 않을 생각이다.
현수가 체크포인트를 최대 k개 건너뛰면서 달릴 수 있다면, 현수가 달려야 하는 최소 거리는 얼마일까?
입력 :
첫 번째 줄에 테스트 케이스의 수 TC가 주어진다. 이후 TC개의 테스트 케이스가 새 줄로 구분되어 주어진다. 각 테스트 케이스는 다음과 같이 구성되었다.
첫 번째 줄에 체크포인트의 수 n과 건너뛸 점의 수 k가 주어진다. ( 0 ≤ k < n ≤ 500 )
이후 n개의 줄에 두 정수 xi, yi가 주어진다. (xi, yi)가 번째 체크포인트의 위치임을 의미한다. (-1000 ≤ xi, yi ≤ 1000)
출력 :
각 테스트 케이스마다 ‘#x’(x는 테스트케이스 번호를 의미하며 1부터 시작한다)를 출력하고,
현수가 체크포인트 k개를 건너뛰고 달릴 수 있는 최소 거리를 출력하라.
풀이 :
역시… DP 문제는 정말 감이 잘 안오는 것 같긴 하다.
DP 문제의 경우 불필요하게 반복되는 부분을 memorization을 통해 효과적으로 구현해야 하는데,
처음에는 해당 체크포인트에서 몇개를 건너뛰어서 오면 거리가 몇인지 저장하려고 했다.
하지만 생각보다 잘 구현되지 않았고, 재귀 방식으로 구현하면서 현재 체크포인트에서 도착점까지 뛰어넘을 수 있는 횟수가 몇 번 남았는지에 따라 최소거리를 저장하였다.
DP[][] 배열의 경우,
DP[k][n]
: 현재 n번 째 체크포인트에 있는 경우, k개의 체크 포인트를 더 뛰어넘을 수 있을 때 최소 거리 저장
이라고 생각하고 memorization을 실행했다.
DP의 경우… 코드가 길지 않고 간단하지만 재귀 방식이나 memorization 방식을 떠올리는 것 자체가 쉽지 않은 것 같다..
연습 더 많이 하자!
코드 :
코드 보기/접기
#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
#include<cmath>
#include<cstring>
#define pii pair<int, int>
#define MAX 987654321
using namespace std;
vector<pii> positions;
int n, jumpnums, dp[500][500];
int calculDist(int firidx, int secidx) {
return abs(positions[firidx].first - positions[secidx].first) + abs(positions[firidx].second - positions[secidx].second);
}
int dpProcess(int remains, int curidx) {
if(curidx == n - 1) return 0;
if(dp[remains][curidx]) return dp[remains][curidx];
dp[remains][curidx] = MAX;
for(int k=0; k<=remains; k++) {
if(curidx + k + 1 >= n) break;
int nextval = dpProcess(remains - k, curidx + k + 1);
dp[remains][curidx] = min(dp[remains][curidx], nextval + calculDist(curidx, curidx + k + 1));
}
return dp[remains][curidx];
}
int testCase() {
int fir, sec;
positions.clear();
memset(dp, 0, sizeof(dp));
cin >> n >> jumpnums;
for(int i=0; i<n; i++){
cin >> fir >> sec;
positions.emplace_back(fir, sec);
}
return dpProcess(jumpnums, 0);
}
int main(int argc, char** argv)
{
int test_case;
int T;
cin>>T;
for(test_case = 1; test_case <= T; ++test_case)
{
cout << '#' << test_case << ' ' << testCase() << '\n';
}
return 0;
}